home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Nuntius 1.2 / src / Nuntius / UHeaderList.cp < prev    next >
Encoding:
Text File  |  1994-02-20  |  9.6 KB  |  377 lines  |  [TEXT/MPS ]

  1. // Copyright © 1992 Peter Speck, speck@dat.ruc.dk. All rights reserved.
  2. // UHeaderList.cp
  3.  
  4. #include "UHeaderList.h"
  5. #include "UOffsetLengthList.h"
  6. #include "Tools.h"
  7. #include "StreamTools.h"
  8.  
  9. #ifndef __XTYPES__
  10. #include "XTypes.h"
  11. #endif
  12.  
  13. #pragma segment MyGroup
  14.  
  15. #define qDebugNewHeaders qDebug & 0
  16. #define qDebugNewHeadersVerbose qDebugNewHeaders & 0
  17.  
  18. const long kCurrentHeaderListVersion = 1;
  19. const long kMinHeaderListVersion = 1;
  20.  
  21. THeaderList::THeaderList()
  22. {
  23. }
  24.  
  25. pascal void THeaderList::Initialize()
  26. {
  27.     inherited::Initialize();
  28.     fDataH = nil;
  29.     fIndexList = nil;
  30.     fFirstID = fLastID = 0;
  31. }
  32.  
  33. void THeaderList::IHeaderList()
  34. {
  35.     inherited::IObject();
  36.     FailInfo fi;
  37.     if (fi.Try())
  38.     {
  39.         fDataH = NewPermHandle(0);
  40.         TOffsetLengthList *list = new TOffsetLengthList();
  41.         list->IOffsetLengthList();
  42.         fIndexList = list;
  43.         fi.Success();
  44.     }
  45.     else // fail
  46.     {
  47.         Free();
  48.         fi.ReSignal();
  49.     }
  50. }
  51.  
  52. pascal void THeaderList::Free()
  53. {
  54.     FreeIfObject(fIndexList); fIndexList = nil;
  55.     fDataH = DisposeIfHandle(fDataH);
  56.     fFirstID = fLastID = 0;
  57.     inherited::Free();
  58. }
  59.  
  60. void THeaderList::DoRead(TStream *aStream)
  61. {
  62.     long version = aStream->ReadLong();
  63.     MyStreamCheckVersion(version, kMinHeaderListVersion, kCurrentHeaderListVersion, "THeaderList");
  64.     MyStreamReadHandle(aStream, fDataH);
  65.     fIndexList->DoRead(aStream);
  66.     fFirstID = aStream->ReadLong();
  67.     fLastID = fFirstID + fIndexList->GetSize() - 1;
  68. #if qDebug
  69.     THeaderList::SanityCheck();
  70. #endif
  71. }
  72.  
  73. void THeaderList::DoWrite(TStream *aStream)
  74. {
  75.     aStream->WriteLong(kCurrentHeaderListVersion);
  76.     MyStreamWriteHandle(aStream, fDataH);
  77.     fIndexList->DoWrite(aStream);
  78.     aStream->WriteLong(fFirstID);
  79. }
  80.  
  81. void THeaderList::DoNeedDiskSpace(long &dataForkBytes)
  82. {
  83.     dataForkBytes += sizeof(long); // version
  84.     dataForkBytes += MyStreamSizeOfHandle(fDataH);
  85.     fIndexList->DoNeedDiskSpace(dataForkBytes);
  86.     dataForkBytes += sizeof(long); // fFirstID
  87. }
  88.  
  89. void THeaderList::DeleteAll()
  90. {
  91.     fFirstID = fLastID = 0;
  92.     fIndexList->DeleteAll();
  93.     SetHandleSize(fDataH, 0);
  94. }
  95.  
  96. void THeaderList::AtGet(long id, HandleOffsetLength &hol)
  97. {
  98. #if qDebug
  99.     if (id < fFirstID || id > fLastID)
  100.     {
  101.         fprintf(stderr, "THeaderList::AtGet, id = %ld, fFirstID = %ld, fLastID = %ld\n", id, fFirstID, fLastID);
  102.         ProgramBreak(gEmptyString);
  103.     }
  104. #endif
  105.     OffsetLength ol;
  106.     fIndexList->AtGet(id - fFirstID + 1, ol);
  107.     hol.fH = fDataH;
  108.     hol.fOffset = ol.fOffset;
  109.     hol.fLength = ol.fLength;
  110. }
  111.  
  112. void THeaderList::AddNewHeaders(Handle h, 
  113.                                                                 long groupFirstID, 
  114.                                                                 long newFirstID, long newLastID)
  115. // The parsing in this proc assumes that the text in h
  116. // is terminated with a null
  117. {
  118. #if qDebug
  119.     SanityCheck();
  120. #endif
  121. #if qDebugNewHeadersVerbose
  122.     DebugDump(true);
  123. #endif
  124.     if (fIndexList->GetSize() == 0 || newFirstID != fLastID + 1) 
  125.     {
  126.     // if we havn't got anything, or the stuff we have is too old
  127.     // then reset the array
  128. #if qDebugNewHeaders
  129.         fprintf(stderr, "THL::ANH, deleting everything\n");
  130.         fprintf(stderr, "(old: %ld -> %ld, new: %ld -> %ld)\n", fFirstID, fLastID, newFirstID, newLastID);
  131. #endif
  132.         fFirstID = newFirstID;
  133.         fLastID = newLastID;
  134.         fIndexList->DeleteAll();
  135.         SetPermHandleSize(fDataH, 0);
  136.     }
  137. // if we have got some headers that's become too old, then delete them
  138.     if (fIndexList->GetSize() > 0 && fFirstID < groupFirstID) 
  139.     {
  140.         long noToDel = groupFirstID - fFirstID;
  141.         long offset;
  142.         long oldDataSize = GetHandleSize(fDataH);
  143.         if (fIndexList->GetSize() == noToDel) 
  144.         {
  145.             offset = oldDataSize;
  146.         }
  147.         else
  148.         {
  149.             offset = fIndexList->OffsetAt(noToDel + 1);
  150.             BytesMove(*fDataH + offset, *fDataH, oldDataSize - offset); // moving down
  151.             long i, maxi = fIndexList->GetSize();
  152.             long *lP = (long*) fIndexList->ComputeAddress(noToDel + 1);
  153.             for (i = noToDel + 1; i <= maxi; i++) // adjust offsets
  154.             {
  155.                 *lP -= offset;
  156.                 lP += 2;
  157.             }
  158.         }
  159. #if qDebugNewHeaders
  160.         fprintf(stderr, "THL::ANH, updating (old: %ld -> %ld, new: %ld -> %ld)\n", fFirstID, fLastID, newFirstID, newLastID);
  161.         fprintf(stderr, "-         noToDel = %ld, offset = %ld, oldDataSize = %ld\n", noToDel, offset, oldDataSize);
  162. #endif
  163.         fFirstID += noToDel;
  164.         fIndexList->DeleteElementsAt(1, noToDel);
  165.         SetPermHandleSize(fDataH, oldDataSize - offset);
  166.     }
  167. #if qDebug
  168.     SanityCheck();
  169. #endif
  170.     fLastID = newLastID;
  171. // add new entries, and set them to zero
  172.     long noIDs = fLastID - fFirstID + 1;
  173.     fIndexList->SetArraySize(noIDs);
  174.     fIndexList->fSize = noIDs;
  175.     long oldSize = GetHandleSize(fDataH);
  176.     long newSize = oldSize + GetHandleSize(h);
  177. #if qDebugNewHeaders
  178.     fprintf(stderr, "-  oldSize = %ld, newSize = %ld, noIDs = %ld\n", oldSize, newSize, noIDs);
  179. #endif
  180.     SetPermHandleSize(fDataH, newSize);
  181.     BytesMove(*h, *fDataH + oldSize, newSize - oldSize);
  182.  
  183. // no mem-move from now!
  184. #if qDebug
  185.     HLockHi(fDataH);
  186. #endif
  187.     register Ptr p = *fDataH + oldSize;
  188.     register long id;
  189.     long lastID = newFirstID - 1;
  190.     register char ch;
  191. #define qGetTime 0
  192. #if qGetTime
  193.     long startTick = TickCount();
  194. #endif
  195.     OffsetLength ol;
  196.     while (*p)
  197.     {
  198. #if qDebug
  199.         Ptr lineStart = p;
  200. #endif
  201.         id = 0;
  202.         ch = *p;
  203.         while (ch > 32) // get id (decimal)
  204.         {
  205.             id *= 10;
  206.             id += ch - '0';
  207.             ch = *++p;
  208.         }
  209.         p++; // step past space
  210.         ol.fOffset = p - *fDataH;
  211.         while (*p != 13)
  212.             ++p; // find text end
  213.         if (id == 0) // ignore, 0 means line without number (eg. foldet line)
  214.         {
  215. #if qDebugNewHeaders
  216.             fprintf(stderr, "THeaderList::ANH, article with id = 0 ignored\n");
  217. #endif
  218.         }
  219.         else if (id > lastID && id <= newLastID) 
  220.         {
  221.             while (++lastID < id)
  222.             {
  223. #if qDebugNewHeadersVerbose
  224.                 fprintf(stderr, "THeaderList::ANH, missed article with id = %ld, put at %ld\n", lastID, lastID - fFirstID + 1);
  225. #endif
  226.                 OffsetLength emptyOL;
  227.                 emptyOL.fOffset = ol.fOffset;
  228.                 emptyOL.fLength = 0;
  229.                 fIndexList->AtPut(lastID - fFirstID + 1, emptyOL);
  230.             }
  231.             ol.fLength = p - *fDataH - ol.fOffset;
  232.             if (ol.fLength == 6 && strncmp(p - 6, "(none)", 6) == 0) 
  233.             {
  234.                 // quick and dirty parsing: kill "(none)" comment
  235.                 // speciality by nntp daemon (vers 1.5.11) XHDR command
  236.                 ol.fOffset += 6;
  237.                 ol.fLength -= 6;
  238.             }
  239. #if qDebugNewHeadersVerbose
  240.             fprintf(stderr, "THeaderList::ANH, article with id = %ld ", id);
  241.             fprintf(stderr, "inserted at %ld: ", id - fFirstID + 1);
  242.             fprintf(stderr, "ol = %ld, %ld, text = ", ol.fOffset, ol.fLength);
  243.             fwrite(*fDataH + ol.fOffset, 1, int(MinMax(0, ol.fLength, 200)), stderr);
  244.             fprintf(stderr, "\n");
  245. #endif
  246.             fIndexList->AtPut(id - fFirstID + 1, ol); // could be optimized
  247.         }
  248.         else
  249.         {
  250. #if qDebug
  251.             fprintf(stderr, "article id %ld out of range, newFirstID = %ld newLastID = %ld, lastID = %ld\n", id, newFirstID, newLastID, lastID);
  252.             fprintf(stderr, "Line: >");
  253.             fwrite(lineStart, 1, p - lineStart, stderr);
  254.             fprintf(stderr, "<\n");
  255. #endif
  256.         }
  257.         ch = *p;
  258.         while (ch == 13 || ch == 10) 
  259.             ch = *++p; // step past CR and/or LF
  260.     }
  261. #if qDebugNewHeaders
  262.     fprintf(stderr, "THeaderList::ANH, after loop: lastID = %ld\n", lastID);
  263. #endif
  264.     while (++lastID <= newLastID)
  265.     {
  266. #if qDebugNewHeadersVerbose
  267.         fprintf(stderr, "THeaderList::ANH, missed article with id = %ld, atput %ld\n", lastID, lastID - fFirstID + 1);
  268. #endif
  269.         OffsetLength emptyOL;
  270.         emptyOL.fOffset = GetHandleSize(fDataH);
  271.         emptyOL.fLength = 0;
  272.         fIndexList->AtPut(lastID - fFirstID + 1, emptyOL);
  273.     }
  274. #if qGetTime
  275.     long ticks = TickCount() - startTick;
  276.     char ss[1000];
  277.     sprintf(ss, "Index ticks: %ld", ticks);
  278.     DebugStr(CStr255(ss));
  279. #endif
  280. #if qDebug
  281.     SanityCheck();
  282.     HUnlock(fDataH);
  283. #endif
  284. }
  285.  
  286. void THeaderList::DebugDump(Boolean verbose)
  287. {
  288. #if qDebug
  289.     verbose = verbose;
  290.     HLock(fDataH);
  291.     fprintf(stderr, "DebugDump of THeaderList at $%lx (%ld headers):\n", long(this), fIndexList->GetSize());
  292.     long size = GetHandleSize(fDataH);
  293.     for (short index = 1; index <= fIndexList->GetSize(); index++)
  294.     {
  295.         fprintf(stderr, "%8ld: ", index);
  296.         OffsetLength ol;
  297.         fIndexList->AtGet(index, ol);
  298.         if (ol.fLength < 0 || ol.fLength > 1000)
  299.         {
  300.             fprintf(stderr, "(bad length: %ld, %ld)\n", ol.fOffset, ol.fLength);
  301.             continue;
  302.         }
  303.         if (ol.fOffset < 0 || ol.fOffset + ol.fLength > size)
  304.         {
  305.             fprintf(stderr, "(bad offset: %ld, %ld)\n", ol.fOffset, ol.fLength);
  306.             continue;
  307.         }
  308.         if (!ol.fLength)
  309.             fprintf(stderr, "<…none…>");
  310.         else
  311.             fwrite(*fDataH + ol.fOffset, 1, int(MinMax(0, ol.fLength, 80)), stderr);
  312.         fprintf(stderr, " (%ld, %ld)\n", ol.fOffset, ol.fLength);
  313.     }
  314.     HUnlock(fDataH);
  315. #else
  316.     verbose = verbose;
  317. #endif
  318. }
  319.  
  320. Boolean THeaderList::SanityCheck()
  321. {
  322.     Boolean isGood = true;
  323. #if qDebug
  324.     if (fIndexList->GetSize() > 0 && fLastID - fFirstID + 1 != fIndexList->GetSize())
  325.     {
  326.         long shouldBe = fIndexList->GetSize() + fFirstID - 1;
  327.         fprintf(stderr, "WRONG: THeaderList::SanityCheck, fLastID is wrong (%ld), should be %ld\n", fLastID, shouldBe);
  328.         fprintf(stderr, "-                                ListSize = %ld, fFirstID = %ld\n", fIndexList->GetSize(), fFirstID);
  329.         isGood = false;
  330.     }
  331.     long size = GetHandleSize(fDataH);
  332.     for (short index = 1; index <= fIndexList->GetSize(); index++)
  333.     {
  334.         OffsetLength ol;
  335.         fIndexList->AtGet(index, ol);
  336. /*
  337.         if (ol.fLength == 0) // compability with old files
  338.         {
  339.             if (index == 1)
  340.                 ol.fOffset = 0;
  341.             else
  342.             {
  343.                 OffsetLength prevOL;
  344.                 fIndexList->AtGet(index - 1, prevOL);
  345.                 ol.fOffset = prevOL.fOffset + prevOL.fLength;
  346.             }
  347.             fIndexList->AtPut(index, ol);
  348.         }                    
  349. */            
  350.         if (ol.fLength < 0 || ol.fLength > 1000)
  351.         {
  352.             fprintf(stderr, "WRONG: THeaderList::SanityCheck: bad header length %ld for index %ld\n", ol.fLength, index);
  353.             isGood = false;
  354.         }
  355.         if (ol.fOffset < 0 || ol.fOffset + ol.fLength > size)
  356.         {
  357.             fprintf(stderr, "WRONG: THeaderList::SanityCheck: bad header offset %ld for index %ld\n", ol.fOffset, index);
  358.             isGood = false;
  359.         }
  360.     }
  361.     if (!isGood)
  362.     {
  363.         DebugDump(true);
  364.         ProgramBreak("THeaderList was bad");
  365.     }
  366. #endif
  367.     return isGood;
  368. }
  369.  
  370. //------------------------------------------------
  371. THeaderList *NewHeaderList()
  372. {
  373.     THeaderList *hl = new THeaderList();
  374.     hl->IHeaderList();
  375.     return hl;
  376. }
  377.